package streamproc;

import java.util.Timer;

import streamproc.buffercomponents.BufferCleaningTimerTask;
import streamproc.buffercomponents.BufferManagerComponent;
import streamproc.eventfiringcomponents.EventFiringComponent;
import streamproc.eventfiringcomponents.EventFiringTimerTask;
import streamproc.filtercomponents.EventFilterComponent;
import streamproc.filtercomponents.EventSetFilterComponent;
import event.Event;

public class Chain {
	private static Chain sInstance = null;

	public static Chain instance() {
		if (sInstance == null)
			sInstance = new Chain();

		return sInstance;
	}

	private static long releaseFirePeriodInMilliSeconds = 100;
	private static long cleanBufferPeriodInMilliSeconds = 100;
	private ChainComponent chainHeader = null;
	private Timer eventFiringTimer = null;
	private Timer bufferCleaningTimer = null;
	private boolean canProcess = false;

	private Chain() {
		reset();
	}

	public void reset() {
		if (eventFiringTimer != null)
			eventFiringTimer.cancel();
		if (bufferCleaningTimer != null)
			bufferCleaningTimer.cancel();

		ChainComponent comp = chainHeader;
		while (comp != null) {
			ChainComponent next = comp.next;
			comp.finalize();
			comp = next;
		}
		chainHeader = null;
		canProcess = false;
		eventFiringTimer = null;
		bufferCleaningTimer = null;
	}

	public void init() {
		CleanerComponent.instance().init();
		EventFilterComponent.instance().init();
		BufferManagerComponent.instance().init();
		SequenceDetectorComponent.instance().init();
		EventSetFilterComponent.instance().init();
		TransformerComponent.instance().init();
		EventFiringComponent.instance().init();

		chainHeader = CleanerComponent.instance();
		CleanerComponent.instance().setNext(
				EventFilterComponent.instance());
		EventFilterComponent.instance().setNext(
				BufferManagerComponent.instance());
		BufferManagerComponent.instance().setNext(
				SequenceDetectorComponent.instance());
		SequenceDetectorComponent.instance().setNext(
				EventSetFilterComponent.instance());
		EventSetFilterComponent.instance().setNext(
				TransformerComponent.instance());
		TransformerComponent.instance()
				.setNext(EventFiringComponent.instance());

		eventFiringTimer = new Timer();
		eventFiringTimer.schedule(new EventFiringTimerTask(), 0,
				releaseFirePeriodInMilliSeconds);

		bufferCleaningTimer = new Timer();
		bufferCleaningTimer.schedule(new BufferCleaningTimerTask(), 0,
				cleanBufferPeriodInMilliSeconds);

		canProcess = true;
	}

	public boolean canProcess() {
		return canProcess;
	}

	public synchronized void processEvent(Event e) {
		chainHeader.processEvent(e);
	}

	public synchronized void processByteArray(long streamID, byte[] data) {
		chainHeader.processByteArray(streamID, data);
	}

	public synchronized void processByteArrayWithTimeStamp(long streamID,
			byte[] data, java.sql.Timestamp timestamp) {
		chainHeader.processByteArrayWithTimestamp(streamID, data, timestamp);
	}
}
